package scuba.DiveBuddy.Class;

import com.google.android.gms.maps.model.LatLng;
import org.joda.time.*;
import scuba.DiveBuddy.Core.Toolbelt;
import scuba.DiveBuddy.Enums.*;
import scuba.DiveBuddy.data.LogEntrySource;

import java.util.Date;

/**
 * @author Alex Anderson
 * @version 1.0
 * @since {4/02/14}
 */
public class LogEntry implements Comparable<LogEntry> {

    //Database Loaded Fields
    private int ID;
    private int DiveNumber;
    private LocalDate DiveDate;
    private LocalTime TimeIn, TimeOut;
    private float MaxDepth;
    private DistanceEnum DepthUnits;
    private DiveTypeEnum DiveType;
    private String Observations;
    private LatLng Location;
    private float StartAir, EndAir;
    private PressureUnitsEnum AirUnits;
    private float Altitude;
    private DistanceEnum AltitudeUnits;
    private WaterTypeEnum WaterType;
    private AirMix AirMix;
    private ExposureTypeEnum ExposureSuit;
    private float ExposureProtectionMM;
    private float SurfaceTemperature, DepthTemperature;
    private TemperatureUnitsEnum TemperatureUnits;
    private float Weight;
    private WeightUnitsEnum WeightUnits;
    private float Visibility;
    private DistanceEnum VisibilityUnits;

    //Fields Not associated with Database
    private PressureGroupEnum PressureGroup;

    //Constructors
    public LogEntry() { }

    /**
        Creates a new log entry, does not commit to database
     */
    public LogEntry(int diveNum, LocalDate diveDate)
    {
        this.ID = -1;
        this.DiveNumber = diveNum;
        this.DiveDate = diveDate;
        this.TimeIn = Toolbelt.Toolkit.getTimeNow().minusMinutes(40);
        this.TimeOut = Toolbelt.Toolkit.getTimeNow().minusMinutes(5);
        this.MaxDepth = 15;
        this.DiveType = DiveTypeEnum.Normal;
        this.Observations = "";
        this.StartAir = 250;
        this.EndAir = 50;
        this.AirUnits = PressureUnitsEnum.BAR;
        this.Altitude = 0;
        this.AltitudeUnits = DistanceEnum.Metres;
        this.WaterType = WaterTypeEnum.SALTWATER;
        this.AirMix = null;
        this.ExposureSuit = ExposureTypeEnum.WETSUIT;
        this.ExposureProtectionMM = 2.5f;
        this.SurfaceTemperature = 25;
        this.DepthTemperature = 20;
        this.TemperatureUnits = TemperatureUnitsEnum.Celsius;
        this.Weight = 0;
        this.WeightUnits = WeightUnitsEnum.kg;
        this.Visibility = 0;
        this.VisibilityUnits = DistanceEnum.Metres;
    }

    //<editor-fold desc="----> Big Constructor">
    public LogEntry(int ID,
            int DiveNumber,
            LocalDate DiveDate,
            LocalTime TimeIn,
            LocalTime TimeOut,
            float MaxDepth,
            DistanceEnum DepthUnits,
            DiveTypeEnum DiveType,
            String Observations,
            LatLng location,
            float StartAir, float EndAir,
            PressureUnitsEnum AirUnits,
            float Altitude,
            DistanceEnum AltitudeUnits,
            WaterTypeEnum WaterType,
            AirMix mix,
            ExposureTypeEnum ExposureSuit,
            float ExposureProtectionMM,
            float SurfaceTemperature, float DepthTemperature,
            TemperatureUnitsEnum TemperatureUnits,
            float Weight,
            WeightUnitsEnum WeightUnits,
            float Visibility,
            DistanceEnum VisibilityUnits)
    {
        this.ID = ID;
        this.DiveNumber = DiveNumber;
        this.DiveDate = DiveDate;
        this.TimeIn = TimeIn;
        this.TimeOut = TimeOut;
        this.MaxDepth = MaxDepth;
        this.DepthUnits = DepthUnits;
        this.DiveType = DiveType;
        this.Observations = Observations;
        this.Location = location;
        this.StartAir = StartAir;
        this.EndAir = EndAir;
        this.AirUnits = AirUnits;
        this.Altitude = Altitude;
        this.AltitudeUnits = AltitudeUnits;
        this.WaterType = WaterType;
        this.AirMix = mix;
        this.ExposureSuit = ExposureSuit;
        this.ExposureProtectionMM = ExposureProtectionMM;
        this.SurfaceTemperature = SurfaceTemperature;
        this.DepthTemperature = DepthTemperature;
        this.TemperatureUnits = TemperatureUnits;
        this.Weight = Weight;
        this.WeightUnits = WeightUnits;
        this.Visibility = Visibility;
        this.VisibilityUnits = VisibilityUnits;
    }
    ///</editor-fold>

    //Methods
    public int getID() { return this.ID; }
    public int getDiveNumber() { return this.DiveNumber; }

    public LatLng getLocationData() { return this.Location; }
    public void setDiveType(DiveTypeEnum type) { this.DiveType = type; }

    public void setDiveDate(LocalDate date) {
        this.DiveDate = date;
    }
    public LocalDate getDiveDate() { return this.DiveDate; }

    public void setTimeIn(LocalTime date) {
        this.TimeIn = date;
    }
    public LocalTime getTimeIn() { return this.TimeIn; }

    public void setTimeOut(LocalTime date) {
        this.TimeOut = date;
    }
    public LocalTime getTimeOut() { return this.TimeOut; }

    public DiveTypeEnum getDiveType() { return this.DiveType; }

    public String getObservations() { return this.Observations; }
    public void setObservations(String observations) { this.Observations = observations;}

    public void setMaxDepth(float depth) {
        this.MaxDepth = depth;
    }
    public float getMaxDepth() { return this.MaxDepth; }
    public void setDepthUnits(DistanceEnum units) {
        this.DepthUnits = units;
    }
    public DistanceEnum getDepthUnits() {
        return this.DepthUnits;
    }

    public void setStartAir(float air) { this.StartAir = air; }
    public void setEndAir(float air) { this.EndAir = air; }
    public void setAirUnits(PressureUnitsEnum units) { this.AirUnits = units;}

    public float getStartAir() { return this.StartAir; }
    public float getEndAir() { return this.EndAir; }
    public PressureUnitsEnum getAirUnits() { return this.AirUnits; }
    public void setAirMix(AirMix mix) { this.AirMix = mix;}
    public AirMix getAirMix() { return this.AirMix; }

    public void setWaterType(WaterTypeEnum type) { this.WaterType = type; }
    public WaterTypeEnum getWaterType() { return this.WaterType; }

    public void setLocationData(LatLng location) {
        this.Location = location;
    }
    public LatLng getLocation() { return this.Location; }

    public float getAltitude() { return this.Altitude; }
    public void setAltitude(float a) { this.Altitude = a; }
    public DistanceEnum getAltitudeUnits() { return this.AltitudeUnits; }
    public void setAltitudeUnits(DistanceEnum units) { this.AltitudeUnits = units; }

    public float getSurfaceTemperature() { return this.SurfaceTemperature; }
    public void setSurfaceTemperature(float temp) { this.SurfaceTemperature = temp; }
    public float getDepthTemperature() { return this.DepthTemperature; }
    public void setDepthTemperature(float temp) { this.DepthTemperature = temp; }
    public TemperatureUnitsEnum getTemperatureUnits() { return this.TemperatureUnits; }
    public void setTemperatureUnits(TemperatureUnitsEnum units) { this.TemperatureUnits = units; }

    public ExposureTypeEnum getExposureSuit() { return this.ExposureSuit; }
    public void setExposureSuit(ExposureTypeEnum type) { this.ExposureSuit = type; }
    public float getExposureProtectionMM() { return this.ExposureProtectionMM; }
    public void setExposureProtectionMM(float mm) { this.ExposureProtectionMM = mm; }

    public float getWeight() { return this.Weight; }
    public void setWeight(float weight) { this.Weight = weight; }
    public WeightUnitsEnum getWeightUnits() { return this.WeightUnits; }
    public void setWeightUnits(WeightUnitsEnum units) { this.WeightUnits = units; }

    public float getVisibility() { return this.Visibility; }
    public void setVisibility(float d) { this.Visibility = d; }
    public DistanceEnum getVisibilityUnits() { return this.VisibilityUnits; }
    public void setVisibilityUnits(DistanceEnum d) { this.VisibilityUnits = d; }

    public PressureGroupEnum getPressureGroup() { return this.PressureGroup; }
    public void setPressureGroup(PressureGroupEnum pg) {
        this.PressureGroup = pg;
    }

    /**
     * Commits changes to the database
     */
    public Boolean Commit() {
        if(this.ID == -1) {
            this.ID = LogEntrySource.CreateLogEntry(this);
            LogEntries.getInstance().InvalidateCache();
            return this.getID() == -1; // i assume this is correct
        }
        else {
            LogEntrySource.UpdateLogEntry(this);
            return true;
        }
    }

    @Override
    public int compareTo(LogEntry logEntry) {
        //return - if we are LESS than logEntry.getDiveNumber
        //return 0 if we are equal
        //return + if we are HIGHER than logEntry.getDiveNumber
        return this.getDiveNumber() - logEntry.getDiveNumber();
    }

    public int getDiveDuration() {
        return Minutes.minutesBetween(getTimeIn(), getTimeOut()).getMinutes();
    }

    public String getDiveHeader() {

        //1/ ge the number of hours which have passed since dive
        DateTime timeOut = getDiveDate().toDateTime(getTimeOut());
        Hours hrsSinceDive = Hours.hoursBetween(timeOut, DateTime.now());

        //if > 24 show date
        if(hrsSinceDive.isGreaterThan(Hours.hours(24))) {
            return Toolbelt.Toolkit.getDateAsString(this.getDiveDate());
        }
        else if(hrsSinceDive.isLessThan(Hours.ONE)) {
            //else if < 1hr ago: show 'x'm Ago
            int mins = Minutes.minutesBetween(DateTime.now(), getTimeOut().toDateTimeToday()).getMinutes();
            return mins + "m Ago";
        }
        else {
            //else show 'x'hrs Ago
            return hrsSinceDive.getHours() + "hrs Ago";
        }
    }
    public String getShortDescription() {
        return getDiveDuration() + " minute dive to " + getMaxDepthString() + " at " + Toolbelt.Toolkit.getTimeAsString(getTimeIn());
    }
    public String getMaxDepthString() {
        return this.MaxDepth + Toolbelt.Toolkit.getDistanceExtension(getDepthUnits());
    }

    @Override
    public String toString() {
        return "Dive: " + getDiveNumber() +
                " | Dive Date: " + Toolbelt.Toolkit.getDateAsString(this.getDiveDate()) +
                " | Time In: " + Toolbelt.Toolkit.getTimeAsString(this.getTimeIn()) +
                " | Time Out: " + Toolbelt.Toolkit.getTimeAsString(this.getTimeOut());
    }
}
